<?php

namespace Desktopd\MUA;


// Message
abstract class Message {
    protected $header;
    protected $body;
    
    
    protected function normalizeNewlines ($str) {
        return preg_replace('/\r\n|\r|\n/', "\r\n", "$str"); // <CR><LF>
        //return preg_replace('~\r\n?~', "\n", "$str"); // <LF>
    }
    
    // XXX: This overwrites everything
    public function importRaw ($data) {
        $message = $this->normalizeNewlines($data);
        $divided = explode("\r\n\r\n", $message, 2);
        $this->header = $divided[0] . "\r\n\r\n";
        // This should not be empty, though
        $this->body = isset($divided[1]) ? $divided[1] : '';
    }
    
    public function exportRaw () {
        return $this->header . $this->body;
    }
    
    public function __toString () {
        return $this->exportRaw();
    }
    
    public function getHeader () {
        return $this->header;
    }
    
    public function getHeaderLines () {
        $header = str_replace("\r\n\r\n", "", $this->getHeader());
        return explode("\r\n", $header);
    }
    
    public function getBody () {
        return $this->body;
    }
    
    public function getBodyLines () {
        $body = $this->getBody();
        return explode("\r\n", $body);
    }
    
    public function searchPrefix ($prefix, $all = true) {
        $prefix = "$prefix";
        $length = strlen($prefix);
        $matches = array();
        if ($length < 1) {
            return $all ? $matches : true;
        }
        
        foreach ($this->getHeaderLines() as $line) {
            if ($prefix === substr($line, 0, $length)) {
                if (!$all) {
                    return $line;
                }
                
                $matches[] = $line;
            }
        }
        
        foreach ($this->getBodyLines() as $line) {
            if ($prefix === substr($line, 0, $length)) {
                if (!$all) {
                    return $line;
                }
                
                $matches[] = $line;
            }
        }
        
        return $all ? $matches : false;
    }
    
    protected function createHeader ($name, $value) {
        $name = trim("$name");
        $value = trim("$value");
        if (!preg_match('~^[-_a-zA-Z0-9]+$~', $name)) return false;
        //if (false !== strpos($value, "\r")) return false;
        //if (false !== strpos($value, "\n")) return false;
        
        return "$name: $value\r\n";
    }
    
    // XXX: no multiline support
    public function prependHeader ($name, $value) {
        $header = $this->createHeader($name, $value);
        if ($header === false) return false;
        
        return $this->header = "{$header}{$this->header}";
    }
    
    // XXX: no multiline support
    public function appendHeader ($name, $value) {
        $header = $this->createHeader($name, $value);
        if ($header === false) return false;
        
        $currentHeader = trim(str_replace("\r\n\r\n", '', $this->header));
        return $this->header = "{$this->header}\r\n{$header}\r\n";
    }
    
    public function getSize () {
        return strlen($this->header) + strlen($this->body);
    }
    
    public function removeHeader ($name) {
        $header = $this->header;
        $name = preg_quote($name, '~');
        $this->header = preg_replace("~^(|.+\\n)$name\s*:\s*.+?\\r?\\n(?:\s+.+?\\r?\\n)*~is", '$1', $header);
    }
    
    public function searchHeader ($name, $all = false) {
        $header = $this->header;
        $lines = explode("\r\n", $header);
        unset($header);
        
        $wanted = false;
        $data = '';
        $found = array();
        foreach ($lines as $line) {
            $line = rtrim($line);
            
            if (preg_match('~^(\s+.*?)$~', $line, $matches)) {
                if (!$wanted) {
                    continue;
                }
                
                $data .= $matches[1];
            } elseif (preg_match('~^([-_A-Za-z0-9]+)\s*:\s*(.+?)$~', $line, $matches)) {
                if ($wanted) {
                    $found[] = $data;
                    if (!$all) {
                        break;
                    }
                }
                
                if (strtolower($matches[1]) !== strtolower($name)) {
                    $wanted = false;
                    continue;
                }
                
                $wanted = true;
                $data = $matches[2];
            } elseif ('' === $line) {
                if ($wanted) {
                    $found[] = $data;
                    $wanted = false;
                }
                
                break;
            }
        }
        
        if ($all) {
            return $found;
        }
        
        if (!isset($found[0])) {
            return false;
        }
        
        return $found[0];
    }
    
    public function getText () {
        $type = $this->searchHeader('Content-Type');
        $encoding = $this->searchHeader('Content-Transfer-Encoding');
        $data = $this->body;
        
        switch (strtolower(trim($encoding))) {
            case 'base64':
                $data = (new Base64($data))->decode();
                break;
            
            case 'quoted-printable':
                $data = (new QuotedPrintable($data))->decode();
                break;
            
        }
        
        if (preg_match('~^text/.+?(?:;\s*[-_a-zA-Z0-9]+=[-_a-zA-Z0-9]+)*;\s*charset="?([-_a-zA-Z0-9]+)"?~', $type, $matches)) {
            $charset = strtolower($matches[1]);
            if (
                $charset !== 'ascii'
                && $charset !== 'us-ascii'
                && $charset !== 'us_ascii'
                && $charset !== 'ascii'
                && $charset !== 'utf-8'
                && $charset !== 'utf8'
                && $charset !== 'utf_8'
            ) {
                $data = mb_convert_encoding($data, 'UTF-8', $charset);
            }
        }
        
        return $data;
    }
}


// vim: ts=4 et ai

